import { argumentHelp } from './index'

/** 通用reducer，用于更新 */
export const COMMON_REDUCER = 'updateState'

function prefixType(type, model) {
  const prefixedType = `${model.namespace}/${type}`
  if (model.reducers?.[prefixedType] || model.effects?.[prefixedType]) {
    return prefixedType
  }
  return type
}

function createEffects({ app, sagaEffects, model }) {
  /** 同一个文件中，不需要加namespace前缀 */
  function put(action) {
    const { type, ...other } = action
    if (!type) {
      throw Error('dispatch: action should be a plain Object with type')
    }
    if (type.indexOf(`${model.namespace}/`) === 0) {
      console.warn(`effects.put: ${type} should not be prefixed with namespace ${model.namespace}`)
    }
    return sagaEffects.put({ type: prefixType(type, model), ...other })
  }

  /** 封装了更新state方法 */
  function update(payload) {
    return put({ type: COMMON_REDUCER, payload })
  }

  /**
   * 通过app._store.dispatch的方式
   * 而不用put
   * 是为了不需要使用 yield take(`${namespace}/${funcitonName}/@@end`) 的方式来等待方法执行结束
   * @param  {...any} props
   * @returns
   */
  function toAction(...props) {
    const { object: payload, string: type = COMMON_REDUCER, boolean: partObj = false } = argumentHelp(props)
    return app._store.dispatch({
      type: type.includes('/') ? type : `${model.namespace}/${type}`,
      payload,
      partObj,
    })
  }

  return { ...sagaEffects, put, update, toAction }
}

const dvaEffectsEnhancer = app => ({
  onEffect: (effect, sagaEffects, model) =>
    function* effectEnhancer(action) {
      yield effect(action, createEffects({ app, sagaEffects, model }))
    },
})

export default dvaEffectsEnhancer
